# -*- coding: utf-8 -*-
'''
@File    :   xcp_slave.py
@Time    :   2024/08/04 17:36:32
@Author  :   None
@Version :   1.0
@Desc    :   python 版本的 xcp_slave
'''

import logging
import os
import queue
import socket
import struct
import sys
import threading
import time
import traceback
import typing
from logging.handlers import RotatingFileHandler

from py_xcp_bridge import xcp_definitions
from py_xcp_bridge.common import get_logger, tool_function
from py_xcp_bridge.common.checksum import CRCType
from py_xcp_bridge.common.hex_io import HexIO

from .common.a2l_io import A2lIO
from .common.datatypes import XCPCharacteristic, XCPMearsurement


class XcpSlave(object):
    def __init__(self, 
                #  ip:str, 
                #  port:int, 
                 a2l_file_path:str, 
                 hex_file_path:str, 
                 cb_on_mearsurement:typing.Optional[typing.Callable[[XCPMearsurement], None]] = None,
                 cb_on_calibration:typing.Optional[typing.Callable[[XCPCharacteristic], None]] = None) -> None:
        # 辅助变量相关
        self._queue_recv_data:queue.Queue = queue.Queue()
        self._queue_send_data:queue.Queue = queue.Queue()
        # self._ip:str = ip
        # self._port:int = port
        self._a2l_file_path:str = a2l_file_path
        self._hex_file_path:str = hex_file_path
        self._is_running:bool = False
        self._ethxcp_tx_counter:int = 0
        self._g_xcp_connection_state = xcp_definitions.XCP_CON_STATE_DISCONNECTED
        self._current_mta:int = 0
        self._hex_io = HexIO(self._hex_file_path)
        self._a2l_io = A2lIO(self._a2l_file_path)
        self._cb_on_mearsurement = cb_on_mearsurement
        self._cb_on_calibration = cb_on_calibration
        self._ip = "0.0.0.0"
        self._port = self._a2l_io.get_xcp_udp_port()
        
        self._logger = get_logger()
        self._logger.info("xcp_slave new instance -------------------------------------------")
            
        # socket 相关
        self._socket_recv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self._socket_recv.bind((self._ip, self._port))
        self._socket_recv.setblocking(False)
        self._socket_recv.settimeout(0.01)
        self._logger.info(f"XCP Slave 启动成功，监听地址为 {self._ip}:{self._port}")
        self._master_ip:str = None
        self._master_port:int = None
        
        # 线程相关
        self._thread_recv_data: threading.Thread = None
        self._thread_send_data: threading.Thread = None
        self._thread_handle_data: threading.Thread = None
    
    def spin(self) -> None:
        self._is_running = True
        self._thread_recv_data = threading.Thread(target=self._thread_func_recv_data, daemon=True)
        self._thread_send_data = threading.Thread(target=self._thread_func_send_data, daemon=True)
        self._thread_handle_data = threading.Thread(target=self._thread_func_handle_data, daemon=True)
        self._thread_recv_data.start()
        self._thread_send_data.start()
        self._thread_handle_data.start()
        self._logger.info("XCP Slave 运行中")
        while True:
            if not self._is_running:
                break
            time.sleep(1)
        time.sleep(1)
        self._socket_recv.close()
        self._logger.info("XCP Slave 退出")
    
    def stop(self) -> None:
        self._is_running = False
    
    def _thread_func_recv_data(self) -> None:
        self._logger.debug("_thread_func_recv_data runing")
        try:
            data:bytes = None
            addr:tuple = None
            while self._is_running:
                try:
                    data, addr = self._socket_recv.recvfrom(2048)
                except:
                    continue
                if (not data):
                    continue
                master_ip:str = addr[0]
                master_port:int = addr[1]
                self._master_ip = master_ip
                self._master_port = master_port

                data_list = [int(x) for x in data]
                self._queue_recv_data.put(data_list)
        except Exception as e:
            e_str = traceback.format_exc()
            self._logger.error(f"_thread_run_recv_data Exception：{e_str}")
        finally:
            self._is_running = False
    
    def _thread_func_send_data(self) -> None:
        self._logger.debug("_thread_func_send_data runing")
        try:
            data_for_send:bytearray = None
            while self._is_running:
                try:
                    data_for_send = self._queue_send_data.get(block=True)
                except:
                    continue
                if (not data_for_send):
                    continue
                if (self._master_ip is None or self._master_port is None):
                    continue
                self._socket_recv.sendto(data_for_send, (self._master_ip, self._master_port))
                self._logger.debug("XCP_Slave2Master：{0}{1}".format(" "*30, ' '.join([format(x, '02X') for x in data_for_send])))
        except Exception as e:
            e_str = traceback.format_exc()
            self._logger.error(f"_thread_run_send_data Exception：{e_str}")
        finally:
            self._is_running = False
    
    def _thread_func_handle_data(self) -> None:
        self._logger.debug("_thread_func_handle_data runing")
        try:
            data_list:typing.List[int] = None
            while self._is_running:
                try:
                    data_list = self._queue_recv_data.get(block=True)
                except:
                    continue
                if (not data_list):
                    continue
                # 解析 XCP 命令
                self._handle_xcp_cmd(data_list)
        except Exception as e:
            e_str = traceback.format_exc()
            self._logger.error(f"_thread_run_handle_data Exception：{e_str}")
        finally:
            self._is_running = False
    
    def _handle_xcp_cmd(self, data_list:typing.List[int]) -> None:
        header_data = data_list[:4]
        cmd_data = data_list[4:]
        cmd = cmd_data[0]
        if (cmd == xcp_definitions.XCP_CMD_CONNECT):
            self._logger.debug("XCP_Master2Slave: {0:<30}{1}".format("XCP_CMD_CONNECT", ' '.join([format(x, '02X') for x in data_list])))
            # 长度校验
            if (len(cmd_data) != xcp_definitions.XCP_CMD_CONNECT_LEN):
                self._logger.error(f"收到 XCP_CMD_CONNECT 指令，但长度不对，收到的数据长度为 {len(data)}，应为 {xcp_definitions.XCP_CMD_CONNECT_LEN}")
                self._send_error_response(xcp_definitions.XCP_ERR_CODE_ERR_OUT_OF_RANGE)
                return
            
            # TODO: 清空队列的数据或者一些标志位
            
            # 处理逻辑
            self._process_cmd_connect(cmd_data[1])
        elif (cmd == xcp_definitions.XCP_CMD_GET_STATUS):
            self._logger.debug(f"XCP_Master2Slave: {'XCP_CMD_GET_STATUS':<30}{' '.join([format(x, '02X') for x in data_list])}")
            self._process_cmd_get_status()
        elif (cmd == xcp_definitions.XCP_CMD_DISCONNECT):
            # TODO: 清空 daq 队列
            self._logger.debug(f"XCP_Master2Slave: {'XCP_CMD_DISCONNECT':<30}{' '.join([format(x, '02X') for x in data_list])}")
            # 处理断开逻辑
            self._process_cmd_disconnect()
        elif (cmd == xcp_definitions.XCP_CMD_SYNCH):
            self._logger.debug(f"XCP_Master2Slave: {'XCP_CMD_SYNCH':<30}{' '.join([format(x, '02X') for x in data_list])}")
            self._send_error_response(xcp_definitions.XCP_ERR_CODE_CMD_SYNCH)
        elif (cmd == xcp_definitions.XCP_CMD_GET_CAL_PAGE):
            self._logger.debug(f"XCP_Master2Slave: {'XCP_CMD_GET_CAL_PAGE':<30}{' '.join([format(x, '02X') for x in data_list])}")
            if (xcp_definitions.XCP_CMD_GET_CAL_PAGE_LEN > len(cmd_data)):
                self._logger.error(f"收到 XCP_CMD_GET_CAL_PAGE 指令，但长度不对，收到的数据长度为 {len(cmd_data)}，应为 {xcp_definitions.XCP_CMD_GET_CAL_PAGE_LEN}")
                self._send_error_response(xcp_definitions.XCP_ERR_CODE_ERR_OUT_OF_RANGE)
                return
            mode = cmd_data[1]
            segment_num = cmd_data[2]
            self._process_cmd_get_cal_page(mode, segment_num)
        elif (cmd == xcp_definitions.XCP_CMD_SET_CAL_PAGE):
            self._logger.debug(f"XCP_Master2Slave: {'XCP_CMD_SET_CAL_PAGE':<30}{' '.join([format(x, '02X') for x in data_list])}")
            # 处理切页
            if (xcp_definitions.XCP_CMD_SET_CAL_PAGE_LEN > len(cmd_data)):
                self._logger.error(f"收到 XCP_CMD_SET_CAL_PAGE 指令，但长度不对，收到的数据长度为 {len(cmd_data)}，应为 {xcp_definitions.XCP_CMD_SET_CAL_PAGE_LEN}")
                self._send_error_response(xcp_definitions.XCP_ERR_CODE_ERR_OUT_OF_RANGE)
                return
            mode = cmd_data[1]
            segment_num = cmd_data[2]
            page_num = cmd_data[3]
            self._process_cmd_set_cal_page(mode, segment_num, page_num)
        elif (cmd == xcp_definitions.XCP_CMD_SET_MTA):
            self._logger.debug(f"XCP_Master2Slave: {'XCP_CMD_SET_MTA':<30}{' '.join([format(x, '02X') for x in data_list])}")
            addr_ext = 0x00
            addr = 0x00
            if (xcp_definitions.XCP_CMD_SET_MTA_LEN > len(cmd_data)):
                self._logger.error(f"收到 XCP_CMD_SET_MTA 指令，但长度不对，收到的数据长度为 {len(cmd_data)}，应为 {xcp_definitions.XCP_CMD_SET_MTA_LEN}")
                self._send_error_response(xcp_definitions.XCP_ERR_CODE_ERR_OUT_OF_RANGE)
                return
            addr_ext = cmd_data[3]
            addr = tool_function.int_list_to_uint32(cmd_data[4:8], "little")
            # self._logger.debug(f"XCP_Master2Slave: XCP_CMD_SET_MTA addr=0x{addr:08X} addr_ext={addr_ext}")
            self._process_cmd_set_mta(addr_ext, addr)
        elif (cmd == xcp_definitions.XCP_CMD_BUILD_CHECKSUM):
            self._logger.debug(f"XCP_Master2Slave: {'XCP_CMD_BUILD_CHECKSUM':<30}{' '.join([format(x, '02X') for x in data_list])}")
            block_size:int = 0x00;
            if (xcp_definitions.XCP_CMD_BUILD_CHECKSUM_LEN > len(cmd_data)):
                self._logger.error(f"收到 XCP_CMD_BUILD_CHECKSUM 指令，但长度不对，收到的数据长度为 {len(cmd_data)}，应为 {xcp_definitions.XCP_CMD_BUILD_CHECKSUM_LEN}")
                self._send_error_response(xcp_definitions.XCP_ERR_CODE_ERR_OUT_OF_RANGE)
                return
            
            block_size = tool_function.int_list_to_uint32(cmd_data[4:8], "little")
            self._process_cmd_build_checksum(block_size)
        elif (cmd == xcp_definitions.XCP_CMD_SHORT_UPLOAD):
            self._logger.debug(f"XCP_Master2Slave: {'XCP_CMD_SHORT_UPLOAD':<30}{' '.join([format(x, '02X') for x in data_list])}")
            if (xcp_definitions.XCP_CMD_SHORT_UPLOAD_LEN > len(cmd_data)):
                self._logger.error(f"收到 XCP_CMD_SHORT_UPLOAD 指令，但长度不对，收到的数据长度为 {len(cmd_data)}，应为 {xcp_definitions.XCP_CMD_SHORT_UPLOAD_LEN}")
                self._send_error_response(xcp_definitions.XCP_ERR_CODE_ERR_OUT_OF_RANGE)
                return
            element_num:int = cmd_data[1]    # 数据单元的长度[AG][1...MAX_CTO-1]
            address_ext:int = cmd_data[3]
            address:int = tool_function.int_list_to_uint32(cmd_data[4:8], "little")
            self._process_cmd_short_upload(element_num, address_ext, address)
        elif (cmd == xcp_definitions.XCP_CMD_DOWNLOAD):
            self._logger.debug(f"XCP_Master2Slave: {'XCP_CMD_DOWNLOAD':<30}{' '.join([format(x, '02X') for x in data_list])}")
            if (xcp_definitions.XCP_CMD_DOWNLOAD_LEN > len(cmd_data)):
                self._logger.error(f"收到 XCP_CMD_DOWNLOAD 指令，但长度不对，收到的数据长度为 {len(cmd_data)}，应为 {xcp_definitions.XCP_CMD_DOWNLOAD_LEN}")
                self._send_error_response(xcp_definitions.XCP_ERR_CODE_ERR_OUT_OF_RANGE)
                return
            number_of_data_element:int                   = cmd_data[1]
            data:typing.List[int]                        = cmd_data[2:]
            self._process_cmd_download(number_of_data_element, data)
        else:
            self._logger.error("收到未知的 XCP 命令：{0:02X}".format(cmd))

    def _process_cmd_connect(self, mode:int) -> None:
        '''
        处理逻辑：
        '''
        # 判断是否可以发送数据
        if (xcp_definitions.XCP_CONNECT_MODE_NORMAL != mode):
            self._logger.error(f"收到 XCP_CMD_CONNECT 指令，但 mode 不正确，收到的数据为 {mode}")
            self._send_error_response(xcp_definitions.XCP_ERR_CODE_ERR_OUT_OF_RANGE)
            return
        
        # 收到 connect 的时候做什么
        resp = [0x00] * xcp_definitions.XCP_CMD_CONNECT_RESP_LEN
        resp[0] = xcp_definitions.XCP_CMD_RES
        
        resource_mask = 0x00
        resource_mask |= xcp_definitions.XCP_RESOURCE_MASK_CAL_PAGE;
        resource_mask |= xcp_definitions.XCP_RESOURCE_MASK_DAQ;
        resp[1] = resource_mask
        
        comm_mode_basic_mask = 0x00
        comm_mode_basic_mask |= xcp_definitions.XCP_COMM_MODE_BASIC_BYTE_ORDER
        comm_mode_basic_mask |= xcp_definitions.XCP_COMM_MODE_BASIC_ADDR_GRANULARITY
        comm_mode_basic_mask |= xcp_definitions.XCP_COMM_MODE_BASIC_SLAVE_BLOCK_MODE
        comm_mode_basic_mask |= xcp_definitions.XCP_COMM_MODE_BASIC_OPTIONAL
        resp[2] = comm_mode_basic_mask
        
        resp[3] = xcp_definitions.XCP_MAX_CTO_LEN
        resp[4] = xcp_definitions.XCP_MAX_CTO_LEN
        resp[5] = 0x00
        resp[6] = xcp_definitions.XCP_PROTOCOL_LAYER_VERSION
        resp[7] = xcp_definitions.XCP_TRANSPORT_LAYER_VERSION
        
        self._g_xcp_connection_state = xcp_definitions.XCP_CON_STATE_CONNECTED
        
        self._xcp_s2m_put_to_queue(resp)
    
    def _process_cmd_get_status(self) -> None:
        resp = [0x00] * xcp_definitions.XCP_CMD_GET_STATUS_RESP_LEN
        
        resp[0] = xcp_definitions.XCP_CMD_RES
        resp[1] = 0x00
        if (self._xcp_any_daq_list_is_running()):
            resp[1] |= xcp_definitions.XCP_GET_STATUS_RESP_CUR_SESSION_STATUS_DAQ_RUNNING_MASK
        resp[2] = 0x00
        resp[3] = 0x00
        resp[4] = 0x00
        resp[5] = 0x00
        self._xcp_s2m_put_to_queue(resp)
    
    def _process_cmd_disconnect(self) -> None:
        self._g_xcp_connection_state = xcp_definitions.XCP_CON_STATE_DISCONNECTED
        self._send_positive_response()
    
    def _process_cmd_sync(self) -> None:
        # 不用做任何事情
        pass
    
    def _process_cmd_get_cal_page(self, mode:int, segment_num:int) -> None:
        """
        这个命令返回当前激活的标定数据页的逻辑号的指定的访问模式，数据页的模式可以是 0x01(ECU access) 和 0x02(XCP access)
        其他所有的值都是无效的

        Args:
            mode (int): 访问模式
            segment_num (int): 逻辑地址号
        """
        # FIXME 应该要实现 ECUMode 或者 XCPMode，暂时只回复 XCPMode
        # 0x01: Mode may be 0x01 (ECU access) or 0x02 (XCP access)
        resp = [0x00] * xcp_definitions.XCP_CMD_GET_CAL_PAGE_RESP_LEN
        resp[0] = xcp_definitions.XCP_CMD_RES
        resp[1] = 0x00
        resp[2] = 0x00
        resp[3] = 0x02
        self._xcp_s2m_put_to_queue(resp)
    
    def _process_cmd_set_cal_page(self, mode:int, segment_num:int, page_num:int) -> None:
        '''
        mode: 0x01: ECU access, 0x02: XCP access
        '''
        # 这里只回复正响应
        self._send_positive_response()
    
    def _process_cmd_set_mta(self, addr_ext:int, addr:int) -> None:
        if (addr_ext != 0x00):
            self._logger.error("当前版本不支持扩展地址")
            # self._send_error_response(xcp_definiti)
        else:
            self._current_mta = addr
            # self._logger.debug(f"当前 MTA 地址为 {self._current_mta:08X}")
            self._send_positive_response()
            
    def _process_cmd_build_checksum(self, block_size:int) -> None:
        """
        返回基于当前 MTA 和 block_size 计算 CRC 的结果
        Args:
            block_size (int): 要计算多长范围内的 CRC
        """
        this_mta = self._current_mta
        # self._current_mta += block_size
        res = self._hex_io.calculate_crc(this_mta, block_size, CRCType.XCP_CRC_32)
        response = [0x00] * xcp_definitions.XCP_CMD_BUILD_CHECKSUM_RESP_LEN
        response[0] = xcp_definitions.XCP_CMD_RES
        response[1] = 0x09                       # XCP_CRC_32, 这里写死是 0x09
        response[2] = 0x00
        response[3] = 0x00
        response[4] = res & 0xFF
        response[5] = (res >> 8) & 0xFF
        response[6] = (res >> 16) & 0xFF
        response[7] = (res >> 24) & 0xFF
        self._xcp_s2m_put_to_queue(response)
        
    def _process_cmd_short_upload(self, element_num:int, address_ext:int, address:int) -> None:
        """
        CommandCode 是 0xF4
        处理 XCP_CMD_SHORT_UPLOAD 指令，根据 address_ext 和 address 作为开始，读取 element_num 个数据，并回复。
        起始于一个地址的指定数据长度的数据块将会返回。MTA 指针设置到指向要上传的数据块的第一个 byte 之前。
        错误处理和返回结构和 UPLOAD 指令相同。
        ELEMENT 是 BYTE，WORD 还是 DWORD 取决于 AG。
        这个指令不支持块传输，并且它在块传输序列中被禁用。

        Args:
            element_num (int): 数据块的长度
            address_ext (int): 扩展地址，1 byte
            address (int): 地址，4 bytes
        """
        # 判断长度是否允许
        if ((0 == element_num) or (xcp_definitions.XCP_CMD_SHORT_UPLOAD_RESP_LEN < element_num)):
            self._logger.error(f"收到错误的 XCP element_num 长度，收到的长度为 {element_num}")
            self._send_error_response(xcp_definitions.XCP_ERR_CODE_ERR_OUT_OF_RANGE)
            return
        # 读取数据
        #               00 01 02 03 04 05 06 07
        # example data: F4 01 00 00 30 FD 01 70
        # 这时候的地址是 7001FD30
        # TODO!: 这里需要根据完成根据 address 获取 观测量名称的步骤
        # mearsure_data = XCPMearsurement(
        #     name="example_data",
        # )
        
        # 辅助变量
        mearsurement_obj = XCPMearsurement(name="", current_value=0x00)
        mearsurement_xcp_obj = self._a2l_io.get_measurement_by_address(address)
        if (mearsurement_xcp_obj is None):
            self._logger.error(f"没有找到对应的测量对象，地址为 {address:08X}")
            self._send_error_response(xcp_definitions.XCP_ERR_CODE_ERR_OUT_OF_RANGE)
            return
        
        mearsurement_obj.name = mearsurement_xcp_obj.name
        mearsurement_obj.data_type = mearsurement_xcp_obj.data_type
        if (self._cb_on_mearsurement):
            self._cb_on_mearsurement(mearsurement_obj)                      # 在回调函数里面填充该测量数据的当前值
        resp = [0x00] * xcp_definitions.XCP_CMD_SHORT_UPLOAD_RESP_LEN
        resp[0] = xcp_definitions.XCP_CMD_RES
        buffer = tool_function.trans_value_to_buffer_by_datatype(
            mearsurement_obj.current_value,
            mearsurement_xcp_obj.data_type,
        )
        resp[1:1+len(buffer)] = buffer
        self._xcp_s2m_put_to_queue(resp, length=element_num + 1)
    
    def _process_cmd_download(self, number_of_data_element:int, data:typing.List[int]) -> None:
        """

        Args:
            address_ext (int): _description_
            address (int): _description_
            data (typing.List[int]): _description_
        """
        """
        1. 根据当前 MTA 地址查找标定量的名称
        2. 在 hexio 中获取之前旧的数据
        3. 如果回调函数可用，则调用回调函数
        4. 修改 HEXIO 的值
        5. 回复正响应
        """
        # resp = [0x00] * xcp_definitions.XCP_CMD_DOWNLOAD_LEN
        # self._logger.debug(f"在 {self._current_mta:08X} 上写入 {len(data)} 个数据")
        address = self._current_mta
        characteristic = XCPCharacteristic(
            name="",
            new_value=0,
            old_value=0,
        )
        a2l_characteristic = self._a2l_io.get_characteristic_by_address(address)
        if (a2l_characteristic == None):
            self._logger.error(f"没有找到对应的 A2L 特征对象，地址为 {address:08X}")
        
        if (a2l_characteristic == None):
            return
        self._logger.debug(f"处理 download number_of_data_element={number_of_data_element} data_length={len(data)}")
        
        # 检验 number_of_data_element 的长度和要修改的标定量的长度是否匹配
        if (number_of_data_element == tool_function.CHARACTERISTIC_RECODER_LAYOUT_MAP_LENGTH[a2l_characteristic.record_layout]):
            # self._logger.debug(f"正在处理快下载，不是更新标定量数据")
            # return
        
            # 获取旧值
            old_data_raw = self._hex_io.get_data(address, number_of_data_element)
            old_data_phy = tool_function.trans_buffer_to_value_by_recoder_layout(
                old_data_raw, a2l_characteristic.record_layout
            )
            new_data_phy = tool_function.trans_buffer_to_value_by_recoder_layout(
                data, a2l_characteristic.record_layout
            )
            
            # 调用回调函数
            characteristic.name = a2l_characteristic.name
            characteristic.new_value = new_data_phy
            characteristic.old_value = old_data_phy
            if (self._cb_on_calibration):
                self._cb_on_calibration(characteristic)

        # 修改 HEXIO 的值
        self._hex_io.set_data(address, data)
        
        # 回复正响应
        self._send_positive_response()
        


    def _send_error_response(self, error_code:int) -> None:
        resp = [0x00] * xcp_definitions.XCP_ERROR_RESP_LEN
        resp[0] = xcp_definitions.XCP_CMD_ERR
        resp[1] = error_code
        self._xcp_s2m_put_to_queue(resp)        
    
    def _send_positive_response(self) -> None:
        resp = [0x00] * xcp_definitions.XCP_POSITIVE_RESP_LEN
        resp[0] = xcp_definitions.XCP_CMD_RES
        self._xcp_s2m_put_to_queue(resp)
    
    def _xcp_s2m_put_to_queue(self, data:typing.Union[bytearray, typing.List[int]], length:int=-1) -> None:
        '''
        处理逻辑：
        1. 计算长度
        2. 计算 counter
        3. 组包
        4. 放入发送队列
        '''
        # 变量声明
        # send_data:typing.List[int] = []
        send_data = bytearray()
        
        # 判断是否有 master_ip 和 master_port
        # if (self._master_ip is None or self._master_port is None):
        #     self._logger.error("没有收到 Master 的连接信息，不能发送数据")
        #     return
        
        # 计算长度
        header = bytearray([0x00] * xcp_definitions.ETHXCP_HEADER_SIZE_BYTES)
        # header = 
        send_length = 0
        if (length == -1):
            send_length = len(data)
        else:
            send_length = length
        header[0] = send_length & 0xff
        header[1] = (send_length >> 8) & 0xff
        header[2] = self._ethxcp_tx_counter & 0xff
        header[3] = (self._ethxcp_tx_counter >> 8) & 0xff
        
        # 组包
        send_data.extend(header)
        if (length == -1):
            send_data.extend(data)
        else:
            send_data.extend(data[:length])  # 只发送指定长度的数据
        
        # 放入发送队列
        self._queue_send_data.put(send_data)
        self._ethxcp_tx_counter += 1
        
    def _xcp_any_daq_list_is_running(self) -> bool:
        '''
        处理逻辑：
        '''
        # FIXME: 这里应该判断是否有 daq 队列正在运行
        return False